import re
import base64
import urllib2

from google.appengine.api import urlfetch


class UnreachableError(Exception):

  def __init__(self, *args):
    super(UnreachableError, self).__init__(*args)


class HTTPRouterApi(object):

  LAN = '/statsifc.html'
  LAN_RESET = '/statsifcreset.html'
  WAN = '/statswan.cmd'
  WAN_RESET = '/statswanreset.html'
  ADSL = '/statsadsl.html'
  COLS = ('Bytes', 'Pkts', 'Errs', 'Drops')
  RESET_TRIES = 5

  ROWRE = r"<tr>.*?<td class='hd'>%s</td>(.*?)</tr>"
  COLSRE = re.compile(r'<td.*?>(.*?)</td>')

  def __init__(self, host, login, password):
    self.host = host
    self.login = login
    self.password = password

  def _BuildUrl(self, path):
    return 'http://%s%s' % (self.host, path)

  def _GetHtml(self, url):
    credentials = base64.encodestring('%s:%s' % (self.login, self.password)).strip()

    try:
      result = urlfetch.fetch(url=url,
                              method=urlfetch.GET,
                              headers={'Authorization': 'Basic %s' % credentials})
    except Exception, e:
      raise UnreachableError(e)

    if result.status_code == 200:
      return result.content
    else:
      raise UnreachableError('not found')

  def GetWanStats(self):
    url = self._BuildUrl(self.WAN)
    html = self._GetHtml(url)

    wan = re.search(r"<td.*?>ppp_.*?</td>(.*?)</tr>", html, re.DOTALL).group(1)
    wan = self.COLSRE.findall(wan)
    wan = map(int, wan)
    stats = {
        'download': dict(zip(self.COLS, wan[:4])),
        'upload': dict(zip(self.COLS, wan[4:])),
    }
    return stats

  def GetLanStats(self):
    url = self._BuildUrl(self.LAN)
    html = self._GetHtml(url)


    ethernet = re.search(self.ROWRE % 'Ethernet', html, re.DOTALL).group(1)
    ethernet = self.COLSRE.findall(ethernet)
    ethernet = map(int, ethernet)
    wireless = re.search(self.ROWRE % 'Wireless', html, re.DOTALL).group(1)
    wireless = self.COLSRE.findall(wireless)
    wireless = map(int, wireless)
    stats = {
        'Ethernet': {
            'download': dict(zip(self.COLS, ethernet[4:])),
            'upload': dict(zip(self.COLS, ethernet[:4])),
        },
        'Wireless': {
            'download': dict(zip(self.COLS, wireless[4:])),
            'upload': dict(zip(self.COLS, wireless[:4])),
        }
    }
    return stats

  def GetAdslStats(self):
    url = self._BuildUrl(self.ADSL)
    html = self._GetHtml(url)

    snr_margin = re.search(r"<tr>.*?<td class='hd'>SNR Margin \(dB\):</td>(.*?)</tr>", html, re.DOTALL).group(1)
    snr_margin = self.COLSRE.findall(snr_margin)
    snr_margin = map(float, [i.replace('&nbsp;', '') for i in snr_margin])

    attenuation = re.search(r"<tr>.*?<td class='hd'>Attenuation \(dB\):</td>(.*?)</tr>", html, re.DOTALL).group(1)
    attenuation = self.COLSRE.findall(attenuation)
    attenuation = map(float, [i.replace('&nbsp;', '') for i in attenuation])
    stats = {
        'SNR Margin': {
            'down': snr_margin[0],
            'up': snr_margin[1],
        },
        'Attenuation': {
            'down': attenuation[0],
            'up': attenuation[1],
        }
    }
    return stats

  def _ResetStats(self, path):
    url = self._BuildUrl(path)
    for i in range(self.RESET_TRIES):
      try:
        self._GetHtml(url)
        return
      except UnreachableError:
        continue

  def ResetLanStats(self):
    self._ResetStats(self.LAN_RESET)

  def ResetWanStats(self):
    self._ResetStats(self.WAN_RESET)
